package cn.xchats.rpc.common.core;

import cn.xchats.rpc.common.util.PropertyUtil;
import com.alibaba.fastjson.JSON;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.stereotype.Service;

/*
 * 节点的路径为:   /node1/node2    注意开头的  / 不能缺失 否则会出错
 *@author teddy
 *@date 2018/6/26
 */
@Service
@SuppressWarnings("all")
public class ZookeeperService {

    private static CuratorFramework zkClient;
    private static String zkAddress;
    private static int zkBaseSleepTimeMs;
    private static int zkMaxRetries;

    private static final int zkBaseSleepTimeMsDefault = 1000;
    private static final int zkMaxRetriesDefault = 3;

    public ZookeeperService() {
        startInit();
    }

    /**
     * 初始化启动必要参数
     */
    private void startInit() {
        zkAddress = PropertyUtil.getProperty("zookeeper.address");
        if (null == zkAddress) {
            throw new NullPointerException("init error : zookeeper server address is not find");
        }
        try {
            zkBaseSleepTimeMs = Integer.valueOf(PropertyUtil.getProperty("zookeeper.baseSleepTimeMs"));
        } catch (NumberFormatException e) {
            zkBaseSleepTimeMs = zkBaseSleepTimeMsDefault;
        }
        try {
            zkMaxRetries = Integer.valueOf(PropertyUtil.getProperty("zookeeper.maxRetries"));
        } catch (NumberFormatException e) {
            zkMaxRetries = zkMaxRetriesDefault;
        }

        zkClient = connection();
    }

    /**
     * 与zookeeper连接
     */
    private CuratorFramework connection() {
        System.out.println("ZookeeperUtil  init ... start ");
        CuratorFramework zkClient;
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(zkBaseSleepTimeMs, zkMaxRetries);
        //zkClient = CuratorFrameworkFactory.newClient(zkAddress, retryPolicy);
        //设置超时时间
        zkClient = CuratorFrameworkFactory.newClient(zkAddress, 1000, 1000, retryPolicy);
        zkClient.start();
        System.out.println("ZookeeperUtil  init ... end");

        System.out.println("正在测试zookeeper连接状态");
        try {
            //确保zk服务地址正确
            zkClient.checkExists().creatingParentContainersIfNeeded().forPath("/");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("zookeeper已连接成功");

        return zkClient;
    }

    /**
     * 获取zk客户端
     */
    public CuratorFramework getConnection() {
        return zkClient;
    }

    /**
     * 转换成zk节点使用的数据类型
     */
    public byte[] convertNodeValue(Object nodeValue) {
        if (null == nodeValue)
            return null;
        return JSON.toJSONString(nodeValue).getBytes();
    }


    /**
     * 创建空节点
     */
    public boolean createEmptyNode(String nodePath) {
        try {
            zkClient.create().forPath(nodePath);
        } catch (Exception e) {
            System.out.println("节点创建失败,请检查节点是否重复.");
            return false;
        }
        return true;
    }

    /**
     * 创建节点
     */
    public boolean createNode(String nodePath, byte[] nodeValue) {
        try {
            if (null == nodeValue) {
                System.out.println("nodeValue is null ");
                return false;
            }
            zkClient.create().forPath(nodePath, nodeValue);
        } catch (Exception e) {
            System.out.println("节点创建失败,请检查节点是否重复.");
            return false;
        }
        return true;
    }

    /**
     * 创建节点
     */
    public boolean createNode(String nodePath, Object nodeValue) {
        byte[] result = convertNodeValue(nodeValue);
        return createNode(nodePath, result);
    }

    /**
     * 创建临时空节点
     */
    public boolean createEphemeralEmptyNode(String nodePath) {
        try {
            zkClient.create().withMode(CreateMode.EPHEMERAL).forPath(nodePath);
        } catch (Exception e) {
            System.out.println("节点创建失败,请检查节点是否重复.");
            return false;
        }
        return true;
    }

    /**
     * 创建临时节点
     */
    public boolean createEphemeralNode(String nodePath, byte[] nodeValue) {
        try {
            if (null == nodeValue) {
                System.out.println("nodeValue is null ");
                return false;
            }
            zkClient.create().withMode(CreateMode.EPHEMERAL).forPath(nodePath, nodeValue);
        } catch (Exception e) {
            System.out.println("节点创建失败,请检查节点是否重复.");
            return false;
        }
        return true;
    }

    /**
     * 创建临时节点
     */
    public boolean createEphemeralNode(String nodePath, Object nodeValue) {
        byte[] result = convertNodeValue(nodeValue);
        return createEphemeralNode(nodePath, result);
    }

    /**
     * 删除节点
     */
    public boolean deleteNode(String nodePath) {
        try {
            zkClient.delete().guaranteed().forPath(nodePath);
        } catch (Exception e) {
            System.out.println("节点删除失败,请检查节点是否存在");
            return false;
        }
        return true;
    }

    /**
     * 修改节点的值为空
     */
    public boolean updateEmptyNode(String nodePath) {
        try {
            zkClient.setData().forPath(nodePath);
        } catch (Exception e) {
            System.out.println("节点修改失败，请检查节点是否存在.");
            return false;
        }
        return true;
    }

    /**
     * 修改节点
     */
    public boolean updateNode(String nodePath, byte[] nodeValue) {
        try {
            if (null == nodeValue) {
                System.out.println("nodeValue is null ");
                return false;
            }
            zkClient.setData().forPath(nodePath, nodeValue);
        } catch (Exception e) {
            System.out.println("节点修改失败，请检查节点是否存在.");
            return false;
        }
        return true;
    }

    /**
     * 修改节点
     */
    public boolean updateNode(String nodePath, Object nodeValue) {
        byte[] result = convertNodeValue(nodeValue);
        return updateNode(nodePath, result);
    }

    /**
     * 查询节点
     */
    public String getNode(String nodePath) {
        try {
            byte[] result = zkClient.getData().forPath(nodePath);
            return new String(result);
        } catch (Exception e) {
            System.out.println("查询出错,请检查节点是否存在");
            return null;
        }
    }

    /**
     * 节点是否存在
     */
    public boolean checkNodePath(String nodePath) {
        try {
            Stat result = zkClient.checkExists().creatingParentContainersIfNeeded().forPath(nodePath);
            if (null == result)
                return false;
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("出现未知异常");
            return false;
        }
    }

}
